﻿using System;

namespace XmlSockets.Internal
{
    /// <summary>
    /// 
    /// </summary>
    internal enum MessageReadState{

        /// <summary>
        /// 
        /// </summary>
        None,

        /// <summary>
        /// 
        /// </summary>
        Completed,

        /// <summary>
        /// 
        /// </summary>
        NotCmpleted,

        /// <summary>
        /// 
        /// </summary>
        NotXmlMessage
    }


    internal sealed class XmlMessageReadBufferdStream
    {
        
        public int Position;

        private byte[] _buffer;

        

        internal bool MessageAvailable;

        public int Capacity
        {
            get
            {
                return _buffer.Length;
            }
        }

        public byte[] GetBuffer()
        {
            return _buffer;

        }

        public  int Length
        {
            get
            {
                return messageLength;
            }
        }

        public  void SetLength(int value)
        {
            this.bufferLength = value;
        }

        private void ExtendBuffer(int extendSize)
        {
            byte[] extendBuffer = new byte[extendSize];
            Array.ConstrainedCopy(_buffer, 0, extendBuffer, 0, _buffer.Length);
            _buffer = extendBuffer;

        }

        internal XmlMessageReadBufferdStream(int receiveBufferSize)
        {
            this.messageLength = 0;
            this.bufferLength = 0;
            this.Position = 0;
            this.MessageAvailable = false;
            this._buffer = new byte[receiveBufferSize];
        }

        public void ReadContent(IXmlSocketReceiveContent content)
        {
            
            if (content.ReceiveLength <= 0) return;
            if (this.bufferLength >= this.Capacity) ExtendBuffer(this.bufferLength + 256);
            if (content.ReceiveLength >= this.Capacity - bufferLength) ExtendBuffer(this.bufferLength + content.ReceiveLength );
            byte[] buffer = GetBuffer();

            int recvLength = (int)(this.bufferLength + content.Read(buffer, bufferLength));
    
            this.SetLength(recvLength);
            
        }

       

        

        internal void ResturctBuffer()
        {
            byte[] buffer = GetBuffer();
            SetMessagePosition(buffer);
            int bufferSize = this.bufferLength - this.Position;
            Array.ConstrainedCopy(buffer, this.Position, buffer, 0, bufferSize);
            this.Position = 0;
            this.bufferLength = bufferSize;
        }

        private void ClearBuffer()
        {
            this.Position = 0;
            this.messageLength = 0;
            this.bufferLength = 0;
            Array.Clear(_buffer, 0, _buffer.Length);
        }
       

        private void SetMessagePosition(byte[] buffer)
        {
            
            for (; this.Position < bufferLength && buffer[this.Position] == XmlSocketConstant.Boundary_Byte; this.Position++) ;
            


        }

        private void SetMessageLength(byte[] buffer)
        {
            
            for (; this.messageLength < this.bufferLength && buffer[this.messageLength] != XmlSocketConstant.Boundary_Byte; this.messageLength++) ;

        }

        private MessageReadState CheckReadByteState(byte[] buffer)
        {
            if (this.Position >= this.bufferLength) return MessageReadState.NotCmpleted;

            if (buffer[this.Position] != XmlSocketConstant.StartXml_Byte) return MessageReadState.NotXmlMessage;

            if (this.Length>= this.bufferLength) return MessageReadState.NotCmpleted;

            if (buffer[this.Length - 1] != XmlSocketConstant.EndXml_Byte) return MessageReadState.NotXmlMessage;

            return MessageReadState.Completed;
        }

        public MessageReadState NextMessage()
        {
            byte[] buffer = this.GetBuffer();
            int positionTmp = this.Position;
            SetMessagePosition(buffer);
            this.messageLength = this.Position;
            SetMessageLength(buffer);
            MessageReadState rslt = CheckReadByteState(buffer);

            switch (rslt)
            {
                case MessageReadState.Completed:

                    MessageAvailable = true;
                    break;

                case MessageReadState.NotXmlMessage:
                    MessageAvailable = false;
                    break;

                case MessageReadState.NotCmpleted:
                    MessageAvailable = false;
                    this.Position = positionTmp;
                    break;


                default:
                    MessageAvailable = false;
                    break;
            }


            return rslt;

        }

        public void AfterRead()
        {
            this.Position = this.Length;
 

        }

        public void Clear()
        {
            ClearBuffer();
        }

        private int messageLength;
        private int bufferLength;
    }
}
